package com.nebula.salary.portal.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nebula.salary.common.constants.Const;
import com.nebula.salary.common.result.ServerResponse;
import com.nebula.salary.common.utils.RedisUtil;
import com.nebula.salary.common.utils.SecurityUtil;
import com.nebula.salary.model.dto.PageDto;
import com.nebula.salary.model.pojo.Salary;
import com.nebula.salary.model.vo.PageResult;
import com.nebula.salary.model.vo.SalaryAnalyzeVo;
import com.nebula.salary.model.vo.SalaryVo;
import com.nebula.salary.portal.mapper.SalaryMapper;
import com.nebula.salary.portal.service.ISalaryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 工资表 服务实现类
 * </p>
 *
 * @author codex
 * @since 2022-01-24
 */
@Service
public class SalaryServiceImpl extends ServiceImpl<SalaryMapper, Salary> implements ISalaryService {
    
    @Resource
    private RedisUtil redisUtil;
    
    /**
     * 查询全部、一年、两年或更多的数据
     * 
     * @param yearCount 查询几年，0代表1年 1代表2年 以此类推
     * @return 工资列表
     */
    @Override
	public List<Salary> getSalaryByYearCount(Integer yearCount) {
		return baseMapper.getSalaryByYearCount(yearCount, SecurityUtil.getUserId());
	}
    
    /**
     * 根据用户ID获取年度工资合计
     *
     * @param userId 用户ID
     * @return 年度工资合计
     */
    @Override
    public List<Map<String, BigDecimal>> getSumSalaryGroupByYear(Long userId) {
        return baseMapper.getSumSalaryGroupByYear(userId);
    }
    
    /**
     * 根据年份查询工资
     *
     * @param year    年份
     * @param pageDto 分页查询数据传输类
     * @return 工资列表
     */
    @Override
    public ServerResponse<PageResult> selectSalaryByYear(Integer year, PageDto pageDto) {
        Long userId = SecurityUtil.getLoginUser().getUser().getUserId();
        
        Page<SalaryVo> page = new Page<>(pageDto.getPage(), pageDto.getLimit());
        IPage<SalaryVo> pageList = baseMapper.selectSalaryByYear(page, year, userId);
        List<SalaryVo> salaryVos = pageList.getRecords();
        assembleSalaryVo(salaryVos);
        
        NumberFormat nf = NumberFormat.getInstance(Locale.CHINA);
        
        // 当前页合计
        BigDecimal reduce = salaryVos.stream().map(Salary::getSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
        
        // 总计
        BigDecimal total = baseMapper.selectSumSalaryByYear(year, userId);
        
        Map<String, Object> map = new HashMap<>(3);
        map.put("result", salaryVos);
        map.put("pageTotal", nf.format(reduce));
        map.put("total", nf.format(total));
        
        return ServerResponse.createBySuccess(new PageResult(pageList.getTotal(), salaryVos.size(), map));
    }
    
    /**
     * 分页查询所有工资
     *
     * @param pageDto 分页查询数据传输类
     * @return 工资列表
     */
    @Override
    public ServerResponse<PageResult> selectAllByPage(PageDto pageDto) {
        Long userId = SecurityUtil.getLoginUser().getUser().getUserId();
        
        Page<SalaryVo> page = new Page<>(pageDto.getPage(), pageDto.getLimit());
        IPage<SalaryVo> allByPage = baseMapper.selectAllByPage(page, userId, pageDto.isAsc() ? "asc" : "desc");
        List<SalaryVo> salaryVos = allByPage.getRecords();
        assembleSalaryVo(salaryVos);
        
        // 当前页合计
        BigDecimal reduce = salaryVos.stream().map(Salary::getSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
        
        // 总计
        BigDecimal total = baseMapper.selectSumSalary(userId);
        
        NumberFormat nf = NumberFormat.getInstance(Locale.CHINA);
        
        Map<String, Object> map = new HashMap<>(3);
        map.put("result", salaryVos);
        map.put("pageTotal", nf.format(reduce));
        map.put("total", nf.format(total));
        
        PageResult pageResult = new PageResult(allByPage.getTotal(), salaryVos.size(), map);
        return ServerResponse.createBySuccess(pageResult);
    }
    
    /**
     * 工资统计
     *
     * @param pageDto 分页查询数据传输类
     * @return 统计结果
     */
    @Override
    public ServerResponse<PageResult> analyze(PageDto pageDto) {
        Long userId = SecurityUtil.getLoginUser().getUser().getUserId();
        Page<SalaryAnalyzeVo> pageSalary = new Page<>(pageDto.getPage(), pageDto.getLimit());
        IPage<SalaryAnalyzeVo> pages = baseMapper.analyze(pageSalary, userId);
        
        List<SalaryAnalyzeVo> records = pages.getRecords();
        assembleSalaryAnalyzeVo(records);
        
        PageResult pageResult = new PageResult(pages.getTotal(), records.size(), records);
        
        // 存入redis缓存中
        redisUtil.setObject(Const.ANALYZE_RESULT_KEY + SecurityUtil.getLoginUser().getUuid(), pageResult, 30, TimeUnit.DAYS);
        
        return ServerResponse.createBySuccess(pageResult);
    }
    
    /**
     * 工资总计
     *
     * @return 工资总计
     */
    @Override
    public BigDecimal getSum() {
        return baseMapper.getSum(SecurityUtil.getUserId());
    }
    
    /**
     * 组装工资统计前端显示类
     *
     * @param salaryAnalyzeVos 工资统计前端显示类集合
     */
    private void assembleSalaryAnalyzeVo(List<SalaryAnalyzeVo> salaryAnalyzeVos) {
        NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.CHINA);
        salaryAnalyzeVos.forEach(salaryAnalyzeVo -> {
            salaryAnalyzeVo.setAvgSalaryMicrometer(nf.format(salaryAnalyzeVo.getAvgSalary()));
            salaryAnalyzeVo.setAvgSalaryWithBenefitsMicrometer(nf.format(salaryAnalyzeVo.getAvgSalaryWithBenefits()));
            salaryAnalyzeVo.setSumSalaryMicrometer(nf.format(salaryAnalyzeVo.getSumSalary()));
            salaryAnalyzeVo.setSumSalaryWithBenefitsMicrometer(nf.format(salaryAnalyzeVo.getSumSalaryWithBenefits()));
            salaryAnalyzeVo.setSumBenefitsMicrometer(nf.format(salaryAnalyzeVo.getSumBenefits()));
        });
    }
    
    /**
     * 组装工资前端显示类
     *
     * @param salaryVos 工资前端显示类
     */
    private void assembleSalaryVo(List<SalaryVo> salaryVos) {
        NumberFormat nf = NumberFormat.getInstance(Locale.CHINA);
        salaryVos.forEach(salaryVo -> {
            if (salaryVo.getSalary() != null) {
                salaryVo.setSalaryMicrometer(nf.format(salaryVo.getSalary()));
            } else {
                salaryVo.setSalaryMicrometer(nf.format(0));
            }
        });
    }
}
